<?php

class DBU_Backup {
    protected $mysql = null;

    function setDb($obj){
        $this->mysql = $obj;
        return $this;
    }


    function getDb(){
        if (!$this->mysql) {
            trigger_error('Mysql Object not set in ' . __CLASS__);
            return false;
        }
        return $this->mysql;
    }


    public function saveTableStructure($table, $file) {
        $structure = $this->getTableStructure($table);
        $this->saveToFile($file, $structure);
    }


    public function saveTableData($table, $file) {
        $data = $this->getTableData($table);
        $this->saveToFile($file, $data);
    }

    /**
    * Writes to file the $table's structure
    * @param string $table The table name
    */
    function getTableStructure($table){

        // Structure Header
        $structure = "-- \n";
        $structure .= "-- Table structure for table `{$table}` \n";
        $structure .= "-- \n\n";
        // Dump Structure

        $structure .= 'DROP TABLE IF EXISTS `'.$table.'`;'."\n";
        $structure .= "CREATE TABLE `".$table."` (\n";

        $result = $this->getDb()->execute('SHOW FIELDS FROM `'.$table.'`');
        if(!$result) {
            return false;
        } else {
            $records = $result->fetchResults();
        }


        foreach ($records as $record) {
            $structure .= '`'.$record['Field'].'` '.$record['Type'];
            if (!empty($record['Default'])) {
                $structure .= ' DEFAULT \''.$record['Default'].'\'';
            }

            if (@strcmp($record['Null'],'YES') != 0) {
                $structure .= ' NOT NULL';
            }

            if (!empty($record['Extra'])) {
                $structure .= ' '.$record['Extra'];
            }

            $structure .= ",\n";
        }

        $structure = @ereg_replace(",\n$", null, $structure);

        // Save all Column Indexes
        $structure .= $this->getSqlKeysTable($table);
        $structure .= "\n)";

        //Save table engine
        $result = $this->getDb()->execute("SHOW TABLE STATUS LIKE '".$table."'");
        if ($result) {
            $record = $result->fetchResult();
            if (!empty($record['Engine'])) {
                $structure .= ' ENGINE='.$record['Engine'];
            }

//            if (!empty($record['Auto_increment'])) {
//                $structure .= ' AUTO_INCREMENT=' . $record['Auto_increment'];
//            }
        }

        $structure .= ";\n\n-- --------------------------------------------------------\n\n";
        return $structure;
    }

    /**
    * Writes to file the $table's data
    * @param string $table The table name
    * @param boolean $hexValue It defines if the output is base 16 or not
    */
    function getTableData($table,$hexValue = true) {
        // Header
        $data = "-- \n";
        $data .= "-- Dumping data for table `$table` \n";
        $data .= "-- \n\n";

        $records = mysql_query('SHOW FIELDS FROM `'.$table.'`');
        $num_fields = @mysql_num_rows($records);
        if ( $num_fields == 0 )
            return false;
        // Field names
        $selectStatement = "SELECT ";
        $insertStatement = "INSERT INTO `$table` (";
        $hexField = array();
        for ($x = 0; $x < $num_fields; $x++) {
            $record = @mysql_fetch_assoc($records);
            if ( ($hexValue) && ($this->isTextValue($record['Type'])) ) {
                $selectStatement .= 'HEX(`'.$record['Field'].'`)';
                $hexField [$x] = true;
            }
            else
                $selectStatement .= '`'.$record['Field'].'`';
            $insertStatement .= '`'.$record['Field'].'`';
            $insertStatement .= ", ";
            $selectStatement .= ", ";
        }
        $insertStatement = @substr($insertStatement,0,-2).') VALUES';
        $selectStatement = @substr($selectStatement,0,-2).' FROM `'.$table.'`';

        $records = @mysql_query($selectStatement);
        $num_rows = @mysql_num_rows($records);
        $num_fields = @mysql_num_fields($records);
        // Dump data
        if ( $num_rows > 0 ) {
            $data .= $insertStatement;
            for ($i = 0; $i < $num_rows; $i++) {
                $record = @mysql_fetch_assoc($records);
                $data .= ' (';
                for ($j = 0; $j < $num_fields; $j++) {
                    $field_name = @mysql_field_name($records, $j);
                    if ( $hexField[$j] && (@strlen($record[$field_name]) > 0) )
                        $data .= "0x".$record[$field_name];
                    else
                        $data .= "'".@str_replace('\"','"',@mysql_escape_string($record[$field_name]))."'";
                    $data .= ',';
                }
                $data = @substr($data,0,-1).")";
                $data .= ( $i < ($num_rows-1) ) ? ',' : ';';
                $data .= "\n";
                //if data in greather than 1MB save
                if (strlen($data) > 1048576) {
                    $this->saveToFile($this->file,$data);
                    $data = '';
                }
            }
            $data .= "\n-- --------------------------------------------------------\n\n";            
        }

        return $data;
    }


    /**
    * @access private
    */
    function getSqlKeysTable ($table) {
        $primary = "";
        unset($unique);
        unset($index);
        unset($fulltext);
        
        $result = $this->getDb()->execute("SHOW KEYS FROM `{$table}`");
        if(!$result) {
            return false;
        } else {
            $records = $result->fetchResults();
        }

        foreach ($records as $record) {
            if (($record['Key_name'] == 'PRIMARY') AND ($record['Index_type'] == 'BTREE')) {
                if ($primary == "") {
                    $primary = "  PRIMARY KEY  (`{$record['Column_name']}`";
                } else {
                    $primary .= ", `{$record['Column_name']}`";
                }
            }

            if (($record['Key_name'] != 'PRIMARY') AND ($record['Non_unique'] == '0') AND ($record['Index_type'] == 'BTREE')) {
                if ((!is_array($unique)) OR ($unique[$record['Key_name']]=="")) {
                    $unique[$record['Key_name']] = "  UNIQUE KEY `{$record['Key_name']}` (`{$record['Column_name']}`";
                } else {
                    $unique[$record['Key_name']] .= ", `{$record['Column_name']}`";
                }
            }

            if (($record['Key_name'] != 'PRIMARY') AND ($record['Non_unique'] == '1') AND ($record['Index_type'] == 'BTREE')) {
                if ((!is_array($index)) OR ($index[$record['Key_name']]=="")) {
                    $index[$record['Key_name']] = "  KEY `{$record['Key_name']}` (`{$record['Column_name']}`";
                } else {
                    $index[$record['Key_name']] .= ", `{$record['Column_name']}`";
                }
            }

            if (($record['Key_name'] != 'PRIMARY') AND ($record['Non_unique'] == '1') AND ($record['Index_type'] == 'FULLTEXT')) {
                if ( (!is_array($fulltext)) OR ($fulltext[$record['Key_name']]=="") ) {
                    $fulltext[$record['Key_name']] = "  FULLTEXT `{$record['Key_name']}` (`{$record['Column_name']}`";
                } else {
                    $fulltext[$record['Key_name']] .= ", `{$record['Column_name']}`";
                }
            }
        }

        $sqlKeyStatement = '';
        // generate primary, unique, key and fulltext
        if ($primary != "") {
            $sqlKeyStatement .= ",\n";
            $primary .= ")";
            $sqlKeyStatement .= $primary;
        }

        if (is_array($unique)) {
            foreach ($unique as $keyName => $keyDef) {
                $sqlKeyStatement .= ",\n";
                $keyDef .= ")";
                $sqlKeyStatement .= $keyDef;

            }
        }

        if (is_array($index)) {
            foreach ($index as $keyName => $keyDef) {
                $sqlKeyStatement .= ",\n";
                $keyDef .= ")";
                $sqlKeyStatement .= $keyDef;
            }
        }

        if (is_array($fulltext)) {
            foreach ($fulltext as $keyName => $keyDef) {
                $sqlKeyStatement .= ",\n";
                $keyDef .= ")";
                $sqlKeyStatement .= $keyDef;
            }
        }
        
        return $sqlKeyStatement;
    }

  /**
    * @access private
    */
    function isTextValue($field_type) {
        switch ($field_type) {
            case "tinytext":
            case "text":
            case "mediumtext":
            case "longtext":
            case "binary":
            case "varbinary":
            case "tinyblob":
            case "blob":
            case "mediumblob":
            case "longblob":
                return True;
                break;
            default:
                return False;
        }
    }

    /**
    * @access private
    */
    function openFile($filename) {
        $file = false;
        if ( $this->compress )
            $file = @gzopen($filename, "w9");
        else
            $file = @fopen($filename, "w");
        return $file;
    }

  /**
    * @access private
    */
    function saveToFile($file, $data) {
        if (file_put_contents($file, $data) === false) {
            trigger_error('Cannot write to file {' . $file . '}', E_USER_ERROR);
        }
        @chmod($file, 0777);
    }

  /**
    * @access private
    */
    function closeFile($file) {
        if ( $this->compress )
            @gzclose($file);
        else
            @fclose($file);
    }
}
